Skip to content

displayport: skip unnecessary DSC for MST modes within link bandwidth#1025

Open
coleleavitt wants to merge 3 commits intoNVIDIA:mainfrom
coleleavitt:fix/mst-dsc-unnecessary-compression
Open

displayport: skip unnecessary DSC for MST modes within link bandwidth#1025
coleleavitt wants to merge 3 commits intoNVIDIA:mainfrom
coleleavitt:fix/mst-dsc-unnecessary-compression

Conversation

@coleleavitt
Copy link

Summary

Add a PBN pre-check in compoundQueryAttachMST() to skip unnecessary DSC compression when the link has sufficient bandwidth for the uncompressed mode.

Problem

The MST mode validation path unconditionally tries DSC when the device supports it, even when the link has sufficient bandwidth. This causes instability through MST hubs and USB-C docks that don't handle DSC negotiation well, manifesting as:

  • Spurious HPD short pulses
  • DPCD AUX channel failures
  • Intermittent display disconnection ("input signal out of range")

The SST path (compoundQueryAttachSST) already handles this correctly by checking willLinkSupportModeSST() before enabling DSC.

Solution

Before entering the DSC path, calculate the PBN required for the uncompressed mode and check if it fits within available local link PBN. If it does, skip DSC and proceed directly to compoundQueryAttachMSTGeneric() for full validation.

This mirrors the SST behavior without introducing state management issues (the PBN pre-check is side-effect-free).

Behavior Preserved

  • Forced DSC (DSC_FORCE_ENABLE): Still enabled
  • DSC_DUAL mode: Still enabled
  • Bandwidth-insufficient modes: DSC still used as fallback
  • Only truly unnecessary DSC (bandwidth sufficient, not forced) is skipped

Testing

Tested on:

  • NVIDIA RTX PRO 4000 Blackwell Generation Laptop GPU
  • Lenovo ThinkPad USB-C Dock Gen 2 (40AS) — DP 1.4 MST hub
  • LEN S27q-10 2560x1440@60Hz monitor
  • Driver 590.48.01 (open kernel modules)

Before: Monitor intermittently disconnects every few seconds with DSC enabled at 10 bpp
After: Stable connection without DSC (mode fits in DP 1.4 HBR3 uncompressed)

Related Issues

Fixes #1024

May help with:

@CLAassistant
Copy link

CLAassistant commented Feb 13, 2026

CLA assistant check
All committers have signed the CLA.

The MST mode validation path in compoundQueryAttachMST() unconditionally
tries DSC when the device supports it, even when the link has sufficient
bandwidth for the uncompressed mode. This can cause instability through
MST hubs and USB-C docks that don't handle DSC negotiation well,
manifesting as spurious HPD short pulses and DPCD AUX channel failures.

Add a PBN pre-check before entering the DSC path: if the uncompressed
mode fits within the available local link PBN, skip DSC and proceed
directly to compoundQueryAttachMSTGeneric() for full validation. This
mirrors the SST behavior in compoundQueryAttachSST() which only enables
DSC when willLinkSupportModeSST() fails.

The pre-check preserves all existing behavior for forced DSC, DSC_DUAL
mode requests, and bandwidth-insufficient cases.

Signed-off-by: Cole Leavitt <cole@unwrap.rs>
@coleleavitt coleleavitt force-pushed the fix/mst-dsc-unnecessary-compression branch from 3291a61 to f77ad61 Compare February 13, 2026 06:27
# tree, the kernel handles BTF generation natively; otherwise add PAHOLE and
# PAHOLE_AWK_PROGRAM assignments to PAHOLE_VARIABLES.
# Kernel 6.15+ uses Makefile.btf + gen-btf.sh instead of pahole-flags.sh.
PAHOLE_VARIABLES=$(if $(or $(wildcard $(KERNEL_SOURCES)/scripts/pahole-flags.sh),$(wildcard $(KERNEL_SOURCES)/scripts/Makefile.btf)),,"PAHOLE=$(AWK) '$(PAHOLE_AWK_PROGRAM)'")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried this change breaks BTF generation support for kernels 6.7 and above. I also don't see any use of gen-btf.sh directly in Makefile.btf for kernels 6.15 and above. Can you describe what issue you ran into that made you author this commit? Also, this should be a separate PR if needed.

https://elixir.bootlin.com/linux/v6.15.11/source/scripts/Makefile.btf

Thanks in advance.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right — this should be a separate PR and I agree it needs more careful validation against 6.7+.

I've split it out into #1038 and removed it from this PR. The BTF commit is no longer in this branch.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried this change breaks BTF generation support for kernels 6.7 and above. I also don't see any use of gen-btf.sh directly in Makefile.btf for kernels 6.15 and above. Can you describe what issue you ran into that made you author this commit? Also, this should be a separate PR if needed.

https://elixir.bootlin.com/linux/v6.15.11/source/scripts/Makefile.btf

Thanks in advance.

It's actually for 7.0 and above. See torvalds/linux@522397d

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I don't understand this at all. It's supposed to exclude c++ from BTF generation but it doesn't do that if pahole-flags.sh is present. (that only excludes rust). Makefile.btf also seems to be a replacement for pahole-flags.sh. Is there something I'm missing here?

// instability through MST hubs and USB-C docks, manifesting as
// spurious HPD short pulses and DPCD AUX channel failures during
// DSC capability negotiation.
//
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the related issue opened,

This causes instability through MST hubs and USB-C docks that don't handle DSC negotiation well, manifesting as spurious HPD short pulses, DPCD AUX channel failures, and intermittent display disconnection.

Monitor intermittently shows "input signal out of range" and disconnects

For some of these, I am not sure how DSC would be related. DSC shouldn't affect DP AUX or HPD. I suspect the "input signal out of range" seen on the monitor is likely due to the a link assessment failure that programs the wrong compression level supported by the sink and this change works around that programming error. Would you be willing to share a log collection using nvidia-bug-report.sh with nvidia_modeset.debug=1, so we can inspect the dplib logging and understand the failure with the display?

As for why we always opportunistically enable DSC in a MST configuration, that is done for a simple software management policy since in most MST setups, DSC will be required.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point on the DSC/AUX/HPD relationship — you may be right that the root cause is a link assessment failure programming the wrong compression level, and skipping DSC just sidesteps it. I'll collect a nvidia-bug-report.sh with nvidia_modeset.debug=1 and share it so we can inspect the dplib logging.

Regarding the opportunistic DSC policy for MST: understood. This change preserves that — it only skips DSC when the uncompressed mode passes the full compoundQueryAttachMSTGeneric validation (local link PBN, watermark, and per-device intermediate branch timeslots). If any check fails, it falls through to the DSC path as before.

Since the original submission, I've added two additional commits to fix bugs in the speculative pre-check:

  1. Fall through to DSC on intermediate hop failure (e91a9fb) — the original pre-check returned the generic result unconditionally, which meant if an intermediate branch had insufficient timeslots, DSC was never tried. Now it only returns on success; failure falls through to DSC.

  2. Save/restore compound query state (223a169) — the speculative compoundQueryAttachMSTGeneric call mutates compoundQueryResult and per-device compound_query_state. On failure, compoundQueryResult was poisoned (permanently false), and intermediate devices retained stale uncompressed timeslot allocations via bandwidthAllocatedForIndex. The DSC path would then either skip those devices or over-count their timeslots. Fixed by saving all state before the speculative call and restoring on failure. Also added an overflow guard — if the MST topology has more devices than the save array can hold, the speculative pre-check is skipped entirely.

The branch now has 3 clean DP commits and the BTF change has been moved to #1038.

@coleleavitt
Copy link
Author

@coderabbitai review

@coleleavitt
Copy link
Author

@cubicdev review

…rmediate hops

The PBN pre-check only validates local (source) link bandwidth before
skipping DSC. In MST daisy-chain or hub topologies, an intermediate
branch link may have fewer timeslots than the local link. When
compoundQueryAttachMSTGeneric fails at an intermediate branch, the mode
is rejected without trying DSC — but DSC compression would reduce the
PBN enough to fit through the bottleneck.

Instead of returning the generic result directly, check if it succeeded:
if so, return true (DSC unnecessary). If not, fall through to the DSC
path which tries 10 bpp then 8 bpp max compression as fallback.

Signed-off-by: Cole Leavitt <cole@unwrap.rs>
… MST pre-check

The speculative uncompressed pre-check calls compoundQueryAttachMSTGeneric
to determine if DSC can be skipped. However, this function mutates shared
state that the subsequent DSC path depends on:

1. compoundQueryResult is set to false on failure but never reset,
   poisoning all subsequent compoundQueryAttachMSTGeneric calls which
   unconditionally return the (now-false) flag.

2. Per-device compound_query_state (timeslots_used_by_query and
   bandwidthAllocatedForIndex) is only partially rolled back on failure.
   Intermediate branch devices between the source and the bottleneck
   retain their uncompressed timeslot allocations. When the DSC path
   calls compoundQueryAttachMSTGeneric again, these devices are skipped
   via the bandwidthAllocatedForIndex bitmask, keeping incorrect
   (too-large) uncompressed allocations instead of the correct
   (smaller) compressed ones.

Fix this by saving all relevant state before the speculative call and
restoring it on failure, so the DSC path always starts from a clean
slate. Also clear pErrorCode on rollback since the speculative failure
is not a real error.
@coleleavitt
Copy link
Author

Bug Report Log (nvidia_modeset.debug=1)

Attached nvidia-bug-report.log.gz collected with nvidia_modeset.debug=1 enabled on kernel 6.19.0 with the patched 590.48.01 open kernel modules (all 3 commits from this PR applied).

System

  • GPU: NVIDIA (ThinkPad P16 Gen 3)
  • Kernel: 6.19.0
  • Driver: 590.48.01 (kernel-open, built from fork with this PR's patches)
  • Displays: 2× Lenovo S27q-10 (2560×1440 @ 60Hz) — one on HDMI-0, one on DP-0.1 (MST, Synaptics hub)

DP Link Status

  • MST topology discovered correctly (Synaptics hub OUI 0x0024cc90)
  • Sink at 0.1 correctly identified as non-DSC-capable
  • Timeslot allocation: Stream 4, First Slot 1, Count 29 (of 63) — bandwidth math checks out for 2560×1440 @ 60Hz @ 24bpp
  • Link trained successfully, ACT received, no fallbacks or retraining
  • DSC correctly not enabled (sink doesn't support it, and bandwidth is sufficient without it)

Notes

  • The Got a short pulse after an unplug or before any connector is active errors during boot are expected MST topology discovery timing — IRQs arrive before the connector is marked active
  • Aux Read from DPCD offset 0x7 failures are transient hub power-up timing, driver recovers

@coleleavitt
Copy link
Author

coleleavitt commented Feb 23, 2026

nvidia-bug-report.log.gz (base64-encoded, 1.7MB): https://gist.github.com/coleleavitt/2fe873fd3dfaaedbac5bc21b37929bff

To decode: base64 -d nvidia-bug-report.log.gz.b64 > nvidia-bug-report.log.gz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MST mode validation unnecessarily enables DSC when link bandwidth is sufficient

4 participants